
// COMMENT THE LINE BELOW TO WORK WITH REAL HARDWARE, and UNCOMMENT IT FOR TEST WITH ONLY THE ARDUINO CONNECTED TO THE COMPUTER, 
// AND USING THE PROCESSING PROGRAM "mirrorSimulator.pde"
//#define NO_HARDWARE

/*
  Spi.cpp - SPI library
  Copyright (c) 2008 Cam Thompson.
  Author: Cam Thompson, Micromega Corporation, <www.micromegacorp.com>
  Version: December 15, 2008

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
  updated by Alexis 26th oct 2009
  configured for Arduino Mega
  
  Use only for MCP4922 Analog to Digital Converter
*/


#include "WProgram.h"
#include "SpiMCP4922.h"

//---------- init function (before it was in the overloaded constructor) -------------------

void SPI::init() // before it was SPI::SPI()
{
  // initialize the SPI pins
  pinMode(SCK_PIN, OUTPUT);
  pinMode(MOSI_PIN, OUTPUT);
  pinMode(MISO_PIN, INPUT);
  pinMode(SS1_PIN, OUTPUT);
  pinMode(SS2_PIN, OUTPUT);
  
  digitalWrite(SS1_PIN, HIGH);
  digitalWrite(SS2_PIN, HIGH);
  

  // enable SPI Master, MSB, SPI mode 0, FOSC/4
  mode(0);
}

//------------------ mode ---------------------------------------------------

void SPI::mode(byte config)
{
  byte tmp;

  // enable SPI master with configuration byte specified
  SPCR = 0;
  SPCR = (config & 0x7F) | (1<<SPE) | (1<<MSTR);
  SPSR |= B00000001;
  tmp = SPSR;
  tmp = SPDR;
}

//------------------ transfer -----------------------------------------------

byte SPI::transfer(byte value)
{
  SPDR = value;
  while (!(SPSR & (1<<SPIF))) ;
  return SPDR;
}

byte SPI::transfer(byte value, byte period)
{
  SPDR = value;
  if (period > 0) delayMicroseconds(period);
  while (!(SPSR & (1<<SPIF))) ;
  return SPDR;
}


void SPI::transfer16Bit(byte upperHalf, byte lowerHalf)
{
  //digitalWrite(SS_PIN, LOW);
  PORTB &= B11111110;
  
  SPDR = upperHalf;
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = lowerHalf;
  while (!(SPSR & (1<<SPIF))) ;
  
  PORTB |= B00000001;
  
  //digitalWrite(SS_PIN, HIGH);
}




//writeOutX and writeOutY create the right logical word to send to the Digital to Analog Converter (MCP4922) using the SPI16bit library.
//  MCP4922 WRITE COMMAND REGISTER:
//  bit15   14   13    12    11    10   ...   1    bit0
//   A/B   BUF   GA   SHDN   D11   D10  ...   D1   D0
//
//  bit15: '0'= write on A; '1'= write on B ("A"= mirror X; "B"= mirror Y)
//  bit14: '0'= unbuffered; '1'= buffered (I use "buffered")
//  bit13: '0'= 2x (VOUT = 2 * VREF * D/4096); '1'= 1x (VOUT = 2 * VREF * D/4096) (I use "gain 2x" because Vref=Vmax/2)
//  bit12: Output Power Down Control bit (here '1' is power on, '0' shut off)


#ifdef NO_HARDWARE

void SPI::writeOutX(int value){
   Serial.print(value, DEC);  // rem: getX gives a float between 0 and 4000
   Serial.print('M'); // M means position of VIRTUAL MIRROR X
}
void SPI::writeOutY(int value){
   Serial.print(value, DEC);  // rem: getX gives a float between 0 and 4000
   Serial.print('N'); // N means position of VIRTUAL MIRROR X
}
#else
//write on the first DAC, output A (mirror X)
void SPI::writeOutX(int value){ // value (an integer, 16 bits), should contain a 12 bits value (0-4095)
  //Set LOW on the Chip Select of the mirrors DAC
  PORTB &= B11111110;// same as digitalWrite(SS1_PIN, LOW)
  
  // ATTN!! The chip select must be LOW during the transfer of the 16 bits (two bytes), and should NOT go HIGH, otherwise the 
  // DAC will start the conversion!!! this is why we rewrote the SPI library here for the MCP4922... Perhaps suggest a change for the Spi.transfer() method?
  
  // First 4 MSB of value, plus MODES:
  // Note: mode b15-b12 is: B0111xxxx (note b15=0 for VoutA--> mirror X)
  SPDR =  ( (byte)(value >> 8) & B00001111 ) | B01110000; //(byte)(value >> 8) | B01110000 & B01111111; 
  while (!(SPSR & (1<<SPIF))) ; // test of end serial output?
  
  // Seconds, 8 LSB bits of value: 
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ; // test of end serial output?
  
  //Set HIGH on the Chip Select of the mirrors DAC (i.e., perform conversion, and disable). 
  PORTB |= B00000001;// same as digitalWrite(SS1_PIN, HIGH)
}

//write on the first DAC, output B (mirror Y)
void SPI::writeOutY(int value){
  //Set LOW on the Chip Select of the mirrors DAC
  PORTB &= B11111110;
  
  // Note: mode b15-b12 is: B1111xxxx (note b15=1 for VoutB--> mirror Y)
  SPDR = ((byte)(value >> 8) & B00001111 ) | B11110000; 
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ;
  
  //Set HIGH on the Chip Select of the mirrors DAC (i.e., perform conversion, and disable).
  PORTB |= B00000001;
}
#endif

//write on the second DAC, output A (red Laser)
void SPI::writeOutR(int value){
  //Set LOW on the Chip Select of the mirrors DAC
  PORTL &= B11111110;
  
  SPDR = (byte)(value >> 8) | B01110000 & B01111111;
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ;
  
  //Set HIGH on the Chip Select of the mirrors DAC
  PORTL |= B00000001;
}


//---------- preinstantiate SPI object --------------------------------------
//SPI Spi = SPI();
